﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using System.Collections;
using NHibernate.Criterion;
using Mailer.Model;
using Mailer.Model.Types;
using System.Web.Security;

namespace Mailer.Security
{
	public class MembershipProvider : System.Web.Security.MembershipProvider
	{
		public MembershipProvider()
		{
			Logger.Debug(typeof(MembershipProvider), "In constructor.");
		}

		public override string ApplicationName
		{
			get
			{
				return "Mailer";
			}
			set
			{
			}
		}

		public override bool ChangePassword(string username, string oldPassword, string newPassword)
		{
			Logger.Debug(typeof(MembershipProvider), "ChangePassword");
			// throw new NotImplementedException();
			return true;
		}

		public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
		{
			Logger.Debug(typeof(MembershipProvider), "ChangePasswordQuestionAndAnswer");
			// throw new NotImplementedException();
			return true;
		}

		public override System.Web.Security.MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out System.Web.Security.MembershipCreateStatus status)
		{
			Logger.Debug(typeof(MembershipProvider), "CreateUser");
			// throw new NotImplementedException();
			System.Web.Security.MembershipUser ret = null;
			status = System.Web.Security.MembershipCreateStatus.ProviderError;

			string hash = SecurityUtilities.HashPassword(password, username);

			ISession sess = SessionUtilities.BeginSession();
			if (sess != null)
			{

				IList users = sess.CreateCriteria(typeof(Mailer.Model.Types.User))
					.Add(Expression.Eq("Username", username))
					.List();

				IList emails = sess.CreateCriteria(typeof(Mailer.Model.Types.User))
					.Add(Expression.Eq("Email", email))
					.List();

				if (users.Count > 0)
				{
					status = System.Web.Security.MembershipCreateStatus.DuplicateUserName;
				}
				else if (emails.Count > 0)
				{
					status = System.Web.Security.MembershipCreateStatus.DuplicateEmail;
				}
				else
				{
					using (ITransaction tt = sess.BeginTransaction())
					{

						User u = new User();
						u.Username = 
							username;
						u.PasswordHash = hash;
						u.Email = email;
						u.State = (int)UserState.Pending;
					//	u.Roles.Clear();
					//	u.Applications.Clear();
					//	u.Properties.Clear();
						sess.Save(u);

						tt.Commit();
					}

					ret = GetUser(username, false);
				}
				
				SessionUtilities.EndSession(sess);
			}

			if (ret != null)
				status = System.Web.Security.MembershipCreateStatus.Success;

			return ret;
		}

		public override bool DeleteUser(string username, bool deleteAllRelatedData)
		{
			Logger.Debug(typeof(MembershipProvider), "DeleteUser"); 

			ISession sess = SessionUtilities.BeginSession();
			if (sess != null)
			{

				using (ITransaction tt = sess.BeginTransaction())
				{
					User user = sess.CreateCriteria(typeof(Mailer.Model.Types.User))
						.Add(Expression.Eq("Username", username))
						.UniqueResult<User>();

					if (user != null)
					{
						user.State = (int)UserState.Deleted;
						sess.Save(user);
					
						tt.Commit();
					}
				}

				SessionUtilities.EndSession(sess);
			}

			return true;
		}

		public override bool EnablePasswordReset
		{
			get
			{
				return false;
				// throw new NotImplementedException();
			}
		}

		public override bool EnablePasswordRetrieval
		{
			get
			{
				return false;
				// throw new NotImplementedException(); 
			}
		}

		public override System.Web.Security.MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
		{
			Logger.Debug(typeof(MembershipProvider), "FindUsersByEmail");
			// throw new NotImplementedException();
			totalRecords = 0;
			System.Web.Security.MembershipUserCollection muc = new System.Web.Security.MembershipUserCollection();
			return muc;
		}

		public override System.Web.Security.MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
		{
			Logger.Debug(typeof(MembershipProvider), "FindUsersByName");
			// throw new NotImplementedException();

			totalRecords = 0;

			System.Web.Security.MembershipUserCollection muc = new System.Web.Security.MembershipUserCollection();

			return muc;
		}

		public override System.Web.Security.MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
		{
			Logger.Debug(typeof(MembershipProvider), "GetAllUsers");
			// throw new NotImplementedException();

			totalRecords = 0;

			System.Web.Security.MembershipUserCollection muc = new System.Web.Security.MembershipUserCollection();

			return muc;
		}

		public override int GetNumberOfUsersOnline()
		{
			Logger.Debug(typeof(MembershipProvider), "GetNumberOfUsersOnline");

			// throw new NotImplementedException();
			return 0;
		}

		public override string GetPassword(string username, string answer)
		{
			Logger.Debug(typeof(MembershipProvider), "GetPassword");
			// throw new NotImplementedException();

			return "";
		}

		public override System.Web.Security.MembershipUser GetUser(string username, bool userIsOnline)
		{
			Logger.Debug(typeof(MembershipProvider), "GetUser");

			MembershipUser ret = null;

			ISession sess = SessionUtilities.BeginSession();
			if (sess != null)
			{

				User user = sess.CreateCriteria(typeof(Mailer.Model.Types.User))
					.Add(Expression.Eq("Username", username))
					.UniqueResult<User>();

				ret = getMembershipUser(user);

				SessionUtilities.EndSession(sess);
			}

			return ret;
		}

		private MembershipUser getMembershipUser(User user)
		{
			MembershipUser ret = new MembershipUser(this.Name, user.Username, user.ID, user.Email, "", "", (user.State == (int)UserState.Active), (user.State == (int)UserState.Deleted), DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue); ;
			return ret;
		}

		public override System.Web.Security.MembershipUser GetUser(object providerUserKey, bool userIsOnline)
		{
			Logger.Debug(typeof(MembershipProvider), "GetUser");

			MembershipUser ret = null;
			if (providerUserKey is Guid)
			{
				ISession sess = SessionUtilities.BeginSession();
				if (sess != null)
				{

					User user = sess.CreateCriteria(typeof(Mailer.Model.Types.User))
						.Add(Expression.Eq("ID", providerUserKey))
						.UniqueResult<User>();

					ret = getMembershipUser(user);

					SessionUtilities.EndSession(sess);
				}
			}

			return ret;
		}

		public override string GetUserNameByEmail(string email)
		{
			Logger.Debug(typeof(MembershipProvider), "GetUserNameByEmail");
			// throw new NotImplementedException();

			return "";
		}

		public override int MaxInvalidPasswordAttempts
		{
			get
			{
				return 10;
				//  throw new NotImplementedException(); 
			}
		}

		public override int MinRequiredNonAlphanumericCharacters
		{
			get
			{
				return 1;
				// throw new NotImplementedException(); 
			}
		}

		public override int MinRequiredPasswordLength
		{
			get
			{
				return 1;
				// throw new NotImplementedException(); 
			}
		}

		public override int PasswordAttemptWindow
		{
			get
			{
				return 0;
				// throw new NotImplementedException(); 
			}
		}

		public override System.Web.Security.MembershipPasswordFormat PasswordFormat
		{
			get
			{
				// throw new NotImplementedException();
				return System.Web.Security.MembershipPasswordFormat.Hashed;
			}
		}

		public override string PasswordStrengthRegularExpression
		{
			get
			{
				// throw new NotImplementedException();
				return ".+";
			}
		}

		public override bool RequiresQuestionAndAnswer
		{
			get
			{
				// throw new NotImplementedException();
				return false;
			}
		}

		public override bool RequiresUniqueEmail
		{
			get
			{
				return false;
				// throw new NotImplementedException();
			}
		}

		public override string ResetPassword(string username, string answer)
		{
			Logger.Debug(typeof(MembershipProvider), "ResetPassword");
			// throw new NotImplementedException();
			return "";
		}

		public override bool UnlockUser(string userName)
		{
			Logger.Debug(typeof(MembershipProvider), "UnlockUser");
			// throw new NotImplementedException();
			return true;
		}

		public override void UpdateUser(System.Web.Security.MembershipUser user)
		{
			Logger.Debug(typeof(MembershipProvider), "UpdateUser");

			ISession sess = SessionUtilities.BeginSession();
			if (sess != null)
			{

				using (ITransaction tt = sess.BeginTransaction())
				{
					User dbuser = sess.CreateCriteria(typeof(Mailer.Model.Types.User))
						.Add(Expression.Eq("ID", user.ProviderUserKey))
						.UniqueResult<User>();

					if (dbuser != null)			
					{

						if (user.IsLockedOut)
							dbuser.State = (int)UserState.Disabled;
						else if (user.IsApproved)
							dbuser.State = (int)UserState.Active;
						else 
							dbuser.State = (int)UserState.Pending;

						dbuser.Email = user.Email;
												
						sess.Save(dbuser);

						tt.Commit();
					}
				}

				SessionUtilities.EndSession(sess);
			}


			// throw new NotImplementedException();
		}

		public override bool ValidateUser(string username, string password)
		{
			Logger.Debug(typeof(MembershipProvider), "ValidateUser");
			// throw new NotImplementedException();
			bool ret = false;

			ISession sess = SessionUtilities.BeginSession();
			if (sess != null)
			{
				string hash = SecurityUtilities.HashPassword(password, username);


				IList users = sess.CreateCriteria(typeof(Mailer.Model.Types.User))
					.Add(Expression.Eq("Username", username))
					.Add(Expression.Eq("PasswordHash", hash))
					.Add(Expression.Eq("State", (int)UserState.Active))
					.List();


				if (users.Count > 0)
					ret = true;
				/*
				{
				Console.WriteLine("Number of users:{0}", users.Count);
				foreach (Mailer.Model.Types.User u in users)
				{
					Console.WriteLine("Id:{0} - Username:{1} - PasswordHash:{2}", u.ID, u.Username, u.PasswordHash);
				}
				*/

				SessionUtilities.EndSession(sess);
			}

			return ret;
		}
	}
}
